#include "config.h"

#include <cctype>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#if CFG_HAVE_STD_RANGES
#include <ranges>
#endif

using namespace cfg;

// 作用：将对象的所有键值对以“key=type/value”的形式打印，用于展示 entries/object_view。
// 参数：
//   v - 指向对象根的视图。
// 返回：无。
static void
dump_object(View & v)
{
    auto ov = v.object_view();
    if (!ov.has_value() || !*ov)
    {
        std::cout << "<not-object>\n";
        return;
    }

    // 遍历对象条目
#if CFG_HAVE_STD_RANGES
    for (const auto & [key, val] : object_entries_view(**ov))
    {
#else
    for (const auto & kv : (**ov).props)
    {
        const std::string & key = kv.first;
        const Value & val = kv.second;
#endif
        std::cout << key << "=";
        if (std::holds_alternative<std::string>(val))
        {
            std::cout << "\"" << std::get<std::string>(val) << "\"";
        }
        else if (std::holds_alternative<int64_t>(val))
        {
            std::cout << std::get<int64_t>(val);
        }
        else if (std::holds_alternative<double>(val))
        {
            std::cout << std::get<double>(val);
        }
        else if (std::holds_alternative<bool>(val))
        {
            std::cout << (std::get<bool>(val) ? "true" : "false");
        }
        else if (std::holds_alternative<std::shared_ptr<const Array>>(val))
        {
            std::cout << "<array>";
        }
        else if (std::holds_alternative<std::shared_ptr<const Object>>(val))
        {
            std::cout << "<object>";
        }
        else
        {
            std::cout << "<null>";
        }
        std::cout << "\n";
    }
}

// 作用：演示 normalize_keys 与路径访问的结合用法（传统路径 + JSON Pointer）。
// 过程：
//  - 将键统一规整为小写；
//  - 通过传统路径与 JSON Pointer 两种方式读取；
//  - 展示 is_null/value_type/entries 等视图能力；
//  - 额外演示 JSON Pointer 的 ~0/~1 解码能力。
static void
run_normalize_and_view_demo()
{
    try
    {
        Builder b;
        b.normalize_keys(
            [](std::string_view k)
            {
        // 将键转换为小写字符串
#if CFG_HAVE_STD_RANGES
                auto lower =
                    k |
                    std::views::transform(
                        [](char c)
                        { return static_cast<char>(std::tolower(static_cast<unsigned char>(c))); });
                return std::ranges::to<std::string>(lower);
#else
                std::string s;
                s.reserve(k.size());
                for (char c : k)
                    s.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
                return s;
#endif
            });

        // 写入大小写混合的键
        // 为确保示例稳定输出，这里直接使用小写路径键名
        b.set("app.name", std::string("CfgWeave"));
        b.set("app.version", int64_t(1));
        b.set("feature.enabled", true);
        b.set("feature.items[0]", std::string("A"));
        b.set("feature.items[1]", std::string("B"));
        // 演示 JSON Pointer 转义：在对象 special 下，创建包含 '/' 与 '~' 的键名
        b.set("special./home", std::string("slash"));  // 键名为 "/home"
        b.set("special.~tilde", std::string("tilde")); // 键名为 "~tilde"

        auto fr = b.freeze();
        if (!fr.has_value())
        {
            std::cout << "freeze error: " << fr.error().size() << "\n";
            return;
        }

        View v(*fr);

        // 传统路径读取
        auto name_view = v.lookup("app.name");
        std::string name_value = "<missing>";
        if (name_view.has_value())
        {
            auto ns = name_view->get_string();
            name_value = ns.has_value() ? *ns : std::string("<type-mismatch>");
        }
        std::cout << "name=" << name_value << '\n';

        auto item1 = v.lookup("feature.items[1]");
        if (item1.has_value())
        {
            auto s = item1->get_string();
            std::cout << "items[1]=" << (s.has_value() ? *s : std::string("<type>")) << '\n';
        }
        else
        {
            std::cout << "items[1]=<missing>\n";
        }

        // JSON Pointer 读取（等价于上面的两条）
        auto name_ptr = v.lookup("/app/name");
        if (name_ptr.has_value())
        {
            auto s = name_ptr->get_string();
            std::cout << "/app/name=" << (s.has_value() ? *s : std::string("<type>")) << '\n';
        }
        auto item1_ptr = v.lookup("/feature/items/1");
        if (item1_ptr.has_value())
        {
            auto s = item1_ptr->get_string();
            std::cout << "/feature/items/1=" << (s.has_value() ? *s : std::string("<type>"))
                      << '\n';
        }

        // JSON Pointer 转义示例：~1 -> '/', ~0 -> '~'
        auto slash_key = v.lookup("/special/~1home");
        std::cout << "/special/~1home="
                  << (slash_key.has_value() && slash_key->get_string().has_value()
                          ? *slash_key->get_string()
                          : std::string("<missing>"))
                  << '\n';
        auto tilde_key = v.lookup("/special/~0tilde");
        std::cout << "/special/~0tilde="
                  << (tilde_key.has_value() && tilde_key->get_string().has_value()
                          ? *tilde_key->get_string()
                          : std::string("<missing>"))
                  << '\n';

        // 追加：JSON Pointer 写入示例
        Builder b2;
#if CFG_HAVE_STD_RANGES
        b2.normalize_keys(
            [](std::string_view k)
            {
                auto lower =
                    k |
                    std::views::transform(
                        [](char c)
                        { return static_cast<char>(std::tolower(static_cast<unsigned char>(c))); });
                return std::ranges::to<std::string>(lower);
            });
#else
        b2.normalize_keys(
            [](std::string_view k)
            {
                std::string s(k);
                for (char & c : s)
                    c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
                return s;
            });
#endif
        b2.set_pointer("//y", int64_t{42});               // 空键名对象成员写入
        b2.set_pointer("/nest/0/1/2", std::string("Z"));  // 深层数组写入（自动扩容）
        b2.set_pointer("/s~1p/~0~/v", std::string("ok")); // 转义键名写入
        auto fr2 = b2.freeze();
        if (fr2.has_value())
        {
            View v2(*fr2);
            auto y = v2.lookup("//y");
            std::cout << "//y="
                      << (y.has_value() && y->get_int64().has_value()
                              ? std::to_string(*y->get_int64())
                              : std::string("<missing>"))
                      << '\n';
            auto z = v2.lookup("/nest/0/1/2");
            std::cout << "/nest/0/1/2="
                      << (z.has_value() && z->get_string().has_value() ? *z->get_string()
                                                                       : std::string("<missing>"))
                      << '\n';
            auto ok = v2.lookup("/s~1p/~0~/v");
            std::cout << "/s~1p/~0~/v="
                      << (ok.has_value() && ok->get_string().has_value() ? *ok->get_string()
                                                                         : std::string("<missing>"))
                      << '\n';
        }

        // 作用：演示 JSON Pointer 写入的错误路径与诊断收集机制。
        // 场景：
        //  - 非 '/' 开头的指针；
        //  - 非法转义（"~x"）；
        //  - 根层直接使用数组索引（无基槽位）；
        //  - 过大的数组索引（演示自动扩容成功，便于对比）。
        // 输出：通过 freeze() 的错误集合打印 code/message/path。
        auto demo_invalid_pointer_writes = []()
        {
            Builder bx;
#if CFG_HAVE_STD_RANGES
            bx.normalize_keys(
                [](std::string_view k)
                {
                    auto lower = k | std::views::transform(
                                         [](char c) {
                                             return static_cast<char>(
                                                 std::tolower(static_cast<unsigned char>(c)));
                                         });
                    return std::ranges::to<std::string>(lower);
                });
#else
            bx.normalize_keys(
                [](std::string_view k)
                {
                    std::string s(k);
                    for (char & c : s)
                        c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
                    return s;
                });
#endif

            // 非 '/' 开头（将记录 InvalidPath）
            bx.set_pointer("not/pointer", std::string("x"));
            // 非法转义（将记录 InvalidPath）
            bx.set_pointer("/~x", int64_t{1});
            // 数组索引非数字（将记录 InvalidPath）
            // 先创建数组，再对数组段使用非数字索引
            // bx.set_pointer("/arr/0", int64_t{0});
            // bx.set_pointer("/arr/xx", std::string("bad-index"));
            // 根层直接使用数组索引（将记录 InvalidPath: array index without base value）
            bx.set_pointer("/0", int64_t{1});
            // 合法数组写入 +
            // 标量下钻导致类型不匹配（在写入端会覆盖还是报错取决于实现；此处追加一次写入制造冲突场景）
            bx.set_pointer("/k", int64_t{7});
            // 在标量下继续作为对象写入键名，当前实现会将标量替换为对象（根据配置与实现），这里再尝试作为数组写入负索引以触发错误
            // 在标量下继续作为对象写入键名，当前实现会将标量替换为对象（根据配置与实现），这里再尝试作为数组写入负索引以触发错误
            // 注意：写入语义下，负索引段不会被视为数组索引（不是纯数字），因此作为对象键处理，不会产生
            // InvalidPath。 下述两行保留为对比说明，不执行： bx.set_pointer("/arr2/0", int64_t{0});
            // bx.set_pointer("/arr2/-1", std::string("neg-index"));
            // 过大索引：应自动扩容成功
            bx.set_pointer("/big/100", std::string("ok-100"));

            auto frozen = bx.freeze();
            if (!frozen.has_value())
            {
                std::cout << "[pointer write errors]\n";
                for (const auto & e : frozen.error())
                {
                    std::cout << "code=" << static_cast<int>(e.code) << ", message=" << e.message
                              << ", path=";
                    if (e.path.empty())
                        std::cout << "<none>";
                    else
                    {
#if CFG_HAVE_STD_RANGES
                        // 使用 ranges::views::join_with 将路径段以 '/' 连接
                        auto joined = e.path | std::views::join_with(std::string_view("/"));
                        std::string path_str = std::ranges::to<std::string>(joined);
                        std::cout << path_str;
#else
                        for (size_t i = 0; i < e.path.size(); ++i)
                        {
                            if (i > 0)
                                std::cout << '/';
                            std::cout << e.path[i];
                        }
#endif
                    }
                    std::cout << '\n';
                }
            }
            else
            {
                // 即使存在错误，若实现仍允许冻结（视实现而定），打印关键验证项
                View vv(*frozen);
                auto ok100 = vv.lookup("/big/100");
                std::cout << "/big/100="
                          << (ok100.has_value() && ok100->get_string().has_value()
                                  ? *ok100->get_string()
                                  : std::string("<missing>"))
                          << '\n';
            }
        };
        demo_invalid_pointer_writes();

        // 展示 value_type 与 is_null
        auto maybe_null = v.lookup("feature.missing");
        std::cout << "feature.missing.is_null="
                  << (maybe_null.has_value() && maybe_null->is_null() ? "true" : "false") << '\n';
        auto vt = v.lookup("feature.enabled");
        std::cout << "feature.enabled.type="
                  << (vt.has_value() && vt->value_type().has_value()
                          ? static_cast<int>(*vt->value_type())
                          : -1)
                  << '\n';

        // entries/object_view 遍历 app 对象
        auto app = v.lookup("app");
        if (app.has_value())
        {
            std::cout << "[app entries]\n";
            dump_object(*app);
        }
    }
    catch (const std::exception & ex)
    {
        // 避免未捕获异常导致示例进程终止，输出可读诊断信息
        std::cout << "exception: " << ex.what() << '\n';
    }
}

// 作用：程序入口，调用 run_normalize_and_view_demo 展示键规整与高级视图能力。
int
main()
{
    run_normalize_and_view_demo();
    return 0;
}
